/**
 *
 */
package MongoDAL;

import Acquaintance.IAMark;
import DALFactory.IDataMapper3;
import Entity.ELocation;
import Entity.EMark;
import Entity.ERankElement;

import com.mongodb.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.bson.types.BasicBSONList;

/**
 * MongoDB数据层部分负责实现IDataMapper3接口的类
 * 
 * @author Administrator
 */
public class MongoDataMapper3 implements IDataMapper3 {
	/**
	 * 
	 * @param UID
	 * @param HID
	 * @param Collection
	 * @return
	 */
	public boolean InsertCat(int UID, int HID, String Collection) {
		// 新建MongoDB语句
		MongoStatement mstm = new MongoStatement();
		// 获取要操作的集合（类似表）
		DBCollection UserColl = mstm.QueryTable("User");
		DBCollection HouseColl = mstm.QueryTable("House");
		DBCollection TraceColl = mstm.QueryTable(Collection);

		// 创建MongoDB文档对象（类似某一行记录表），在这里是创建查询条件
		DBObject user = new BasicDBObject();
		DBObject house = new BasicDBObject();

		// 文档记录（类似SQL语句的查询条件）
		user.put("UID", UID);
		house.put("_id", HID);

		// 获得满足指定条件的对象
		DBObject userValue = UserColl.findOne(user);
		DBObject HouseValue = HouseColl.findOne(house);

		if (userValue == null || HouseValue == null) {
			mstm = null;
			return false;
		} else {
			InsertMetaData(HID,Collection);
			// 将找到的某一记录作为，参照对象（类似外键）
			DBRef UserDbf = new DBRef(UserColl.getDB(), "User",
					userValue.get("UID"));
			DBRef HouseDbf = new DBRef(HouseColl.getDB(), "House",
					HouseValue.get("_id"));
			DBRef[] HouseDbfs = { HouseDbf };

			// trace为要插入的对象
			DBObject trace = new BasicDBObject();
			trace.put("UID", UserDbf);
			DBObject obj = TraceColl.findOne(trace);
			// 加入这个文档已经存在，比如某个用户有收藏房子A，同时又收藏了房子B 则
			// 先查找到trace这个对象，然后原始的记录基础上插入房子B
			
		
			
			if (obj != null) {
				DBObject InsertHouse = new BasicDBObject();
				DBObject InsertValue = new BasicDBObject();
				InsertHouse.put("HID", HouseDbf);
				// 插入新的房子对象
				InsertValue.put("$addToSet", InsertHouse);
				TraceColl.update(trace, InsertValue);
			} else {
				trace.put("UID", UserDbf);
				trace.put("HID", HouseDbfs);
				TraceColl.insert(trace);
			}
		}
		mstm = null;
		return true;
	}

	/**
	 * 
	 * @param UID
	 * @param Collection
	 * @return
	 */
	public ArrayList<Integer> getLog(int UID, String Collection) {
		ArrayList<Integer> result = new ArrayList<Integer>();
		MongoStatement mstm = new MongoStatement();
		DBCollection FavouColl = mstm.QueryTable(Collection);
		DBCollection UserColl = mstm.QueryTable("User");
		DBObject userValue = UserColl.findOne(new BasicDBObject("UID", UID));
		DBRef UserDbf = new DBRef(UserColl.getDB(), "User",
				userValue.get("UID"));

		DBObject trace = new BasicDBObject();
		trace.put("UID", UserDbf);
		DBCursor cur = FavouColl.find(trace);

		while (cur.hasNext()) {
			DBObject House = (DBObject) cur.next();
			BasicDBList HIDList = (BasicDBList) House.get("HID");
			for (int i = 0; i < HIDList.size(); i++) {
				DBRef HouseObj = (DBRef) HIDList.get(i);
				String HID = HouseObj.fetch().get("_id").toString();
				int hid = Integer.parseInt(HID);
				result.add(hid);
			}
		}
		mstm = null;
		return result;
	}

	/**
	 * 
	 * @param mark
	 * @return
	 */
	public boolean InsertMark(IAMark mark) {
		MongoStatement mstm = new MongoStatement();
		DBCollection UserColl = mstm.QueryTable("User");
		DBCollection TraceColl = mstm.QueryTable("Mark");
		DBObject user = new BasicDBObject();
		user.put("UID", mark.getUID());

		DBObject userValue = UserColl.findOne(user);

		if (userValue == null) {
			mstm = null;
			return false;
		} else {
			DBRef UserDbf = new DBRef(UserColl.getDB(), "User",
					userValue.get("UID"));
			DBObject trace = new BasicDBObject();
			DBObject markObject = new BasicDBObject();

			markObject.put("lat", mark.getLocation().getLat());
			markObject.put("lng", mark.getLocation().getLng());
			markObject.put("Title", mark.getTitle());
			markObject.put("Context", mark.getContext());

			DBCursor cur = TraceColl.find()
					.sort(new BasicDBObject("Mark.MID", -1)).limit(1);
			DBObject UMID = (DBObject) cur.next();
			BasicBSONList markst = (BasicBSONList) UMID.get("Mark");
			String midString = ((DBObject) markst.get(markst.size() - 1)).get(
					"MID").toString();
			float MID = Float.parseFloat(midString);
			int mid = (int) MID;
			mid++;
			markObject.put("MID", mid);

			DBObject[] marks = { markObject };
			trace.put("UID", UserDbf);
			DBObject obj = TraceColl.findOne(trace);

			if (obj != null) {

				DBObject InsertValue = new BasicDBObject();
				DBObject MarkValue = new BasicDBObject();
				MarkValue.put("Mark", markObject);
				InsertValue.put("$push", MarkValue);
				TraceColl.update(trace, InsertValue);
			} else {
				trace.put("UID", UserDbf);
				trace.put("Mark", marks);
				TraceColl.insert(trace);
			}
		}
		mstm = null;
		return true;
	}

	/**
	 * 
	 * @param UID
	 * @return
	 */
	public ArrayList<IAMark> getMark(int UID) {
		ArrayList<IAMark> result = new ArrayList<IAMark>();
		MongoStatement mstm = new MongoStatement();
		DBCollection FavouColl = mstm.QueryTable("Mark");
		DBCollection UserColl = mstm.QueryTable("User");

		DBObject userValue = UserColl.findOne(new BasicDBObject("UID", UID));
		DBRef UserDbf = new DBRef(UserColl.getDB(), "User",
				userValue.get("UID"));

		DBObject trace = new BasicDBObject();
		trace.put("UID", UserDbf);
		DBCursor cur = FavouColl.find(trace);

		while (cur.hasNext()) {
			DBObject Mark = (DBObject) cur.next();
			BasicDBList HIDList = (BasicDBList) Mark.get("Mark");
			for (int i = 0; i < HIDList.size(); i++) {
				EMark mark = new EMark();
				DBObject MarkObj = (DBObject) HIDList.get(i);
				String Context = MarkObj.get("Context").toString();
				String Title = MarkObj.get("Title").toString();
				double lat = Double.parseDouble(MarkObj.get("lat").toString());
				double lng = Double.parseDouble(MarkObj.get("lng").toString());
				float MID = Float.parseFloat(MarkObj.get("MID").toString());
				int mid = (int) MID;
				mark.setContext(Context);
				mark.setTitle(Title);
				mark.setUID(UID);
				mark.setMID(mid);
				mark.setLocation(new ELocation(lat, lng));
				result.add(mark);
			}
		}
		mstm = null;
		return result;
	}

	public int getUserCollectionByHID(int HID, String Collection) {
		int result = 0;
		String Result= getMetaData(HID,Collection).get("HouseCount").toString();
		result=Integer.parseInt(Result);
		return result;
	}
	
	
	public List<ERankElement> getUserCollectionRank(String Collection)
	{
		MongoStatement mstm = new MongoStatement();
		List<ERankElement> result=new ArrayList<ERankElement>();
		// 获取要操作的集合（类似表）
		DBCollection TraceColl = mstm.QueryTable(Collection);
		DBObject root=TraceColl.findOne(new BasicDBObject("Title","MetaData"));
		BasicDBList HouseList=(BasicDBList)root.get("HouseList");
		for(Object obj:HouseList)
		{
			ERankElement element=new ERankElement();
			DBObject doc=(DBObject)obj;
			DBRef HouseRef=(DBRef)doc.get("HouseRef");
			element.setHID((int)Float.parseFloat(HouseRef.getId().toString()));
			element.setMark((int)Float.parseFloat(doc.get("HouseCount").toString()));
			result.add(element);
		}
		mstm=null;
		Collections.sort(result);
		return result;
		
	}

	/**
	 * @param HID
	 * @param Collection
	 */
	private void InsertMetaData(int HID, String Collection) {
		MongoStatement mstm = new MongoStatement();
		// 获取要操作的集合（类似表）
		DBCollection HouseColl = mstm.QueryTable("House");
		DBCollection TraceColl = mstm.QueryTable(Collection);

		DBObject house = new BasicDBObject();
		DBObject houseValue = new BasicDBObject();

		house.put("_id", HID);
		houseValue = HouseColl.findOne(house);

		DBRef houseRef = new DBRef(HouseColl.getDB(), "House",
				houseValue.get("_id"));
		DBObject oldObject = getMetaData(HID, Collection);

		if (!metaDocument(Collection)) {
			DBObject element = new BasicDBObject();
			element.put("HouseRef", houseRef);

			element.put("HouseCount", 1);
			DBObject[] elements = { element };
			DBObject target = new BasicDBObject();
			target.put("HouseList", elements);
			target.put("Title", "MetaData");
			TraceColl.insert(target);
			mstm=null;

		} else if (oldObject != null) {
			DBObject insertValue = new BasicDBObject();
			insertValue.put("HouseList.$.HouseCount", 1);
			DBObject inc = new BasicDBObject();
			inc.put("$inc", insertValue);
			DBObject pos = new BasicDBObject();
			pos.put("HouseList.HouseRef", houseRef);

			TraceColl.update(pos, inc);
			mstm=null;
		} else {

			DBObject target = new BasicDBObject();
			target.put("Title", "MetaData");
			DBObject result = TraceColl.findOne(target);

			DBObject updateValue = new BasicDBObject();
			updateValue.put("HouseRef", houseRef);
			updateValue.put("HouseCount", 1);

			DBObject houseList = new BasicDBObject();
			houseList.put("HouseList", updateValue);
			DBObject Push = new BasicDBObject();

			Push.put("$push", houseList);

			TraceColl.update(result, Push);
			mstm=null;
		}
	}

	private boolean metaDocument(String Collection) {
		MongoStatement mstm = new MongoStatement();
		DBCollection TraceColl = mstm.QueryTable(Collection);
		DBObject exits = new BasicDBObject();
		exits.put("$exists", true);
		DBObject target = new BasicDBObject();
		target.put("HouseList", exits);
		int result = TraceColl.find(target).count();
		if (result >= 1)
			return true;
		else
			return false;
	}

	private DBObject getMetaData(int HID, String Collection) {
		MongoStatement mstm = new MongoStatement();
		// 获取要操作的集合（类似表）
		DBCollection HouseColl = mstm.QueryTable("House");
		DBCollection TraceColl = mstm.QueryTable(Collection);

		DBObject house = new BasicDBObject();
		DBObject houseValue = new BasicDBObject();

		house.put("_id", HID);
		houseValue = HouseColl.findOne(house);

		DBRef houseRef = new DBRef(HouseColl.getDB(), "House",
				houseValue.get("_id"));

		DBObject HouseRef = new BasicDBObject();
		HouseRef.put("HouseRef", houseRef);

		DBObject elemMacth = new BasicDBObject();
		elemMacth.put("$elemMatch", HouseRef);

		DBObject HouseList = new BasicDBObject();
		HouseList.put("HouseList", elemMacth);
		DBObject result = new BasicDBObject();
		result = TraceColl.findOne(HouseList);
		mstm = null;
		return result;
	}

	private boolean checkMetaData(int HID, String Collection) {
		MongoStatement mstm = new MongoStatement();
		// 获取要操作的集合（类似表）
		DBCollection HouseColl = mstm.QueryTable("House");
		DBCollection TraceColl = mstm.QueryTable(Collection);

		DBObject house = new BasicDBObject();
		DBObject houseValue = new BasicDBObject();

		house.put("_id", HID);
		houseValue = HouseColl.findOne(house);

		DBRef houseRef = new DBRef(HouseColl.getDB(), "House",
				houseValue.get("_id"));

		DBObject HouseRef = new BasicDBObject();
		HouseRef.put("HouseRef", houseRef);

		DBObject elemMacth = new BasicDBObject();
		elemMacth.put("$elemMatch", HouseRef);

		DBObject HouseList = new BasicDBObject();
		HouseList.put("HouseList", elemMacth);
		System.out.println(HouseList);
		if (TraceColl.findOne(HouseList) == null) {
			mstm = null;
			return false;
		} else {
			mstm = null;
			return true;
		}
	}

	public static void main(String[] args) {
		MongoDataMapper3 m3 = new MongoDataMapper3();
		m3.InsertMetaData(363, "Favourite");
		System.out.println();

	}

}
